home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / network / ncsasock / sock_utl.c < prev    next >
Text File  |  1996-07-05  |  9KB  |  429 lines

  1. /*
  2.  * BSD-style socket emulation library for the Mac
  3.  * Original author: Tom Milligan
  4.  * Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
  5.  *
  6.  * This source file is placed in the public domian.
  7.  * Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
  8.  *
  9.  *      National Center for Supercomputing Applications
  10.  *      152 Computing Applications Building
  11.  *      605 E. Springfield Ave.
  12.  *      Champaign, IL  61820
  13.  */
  14.  
  15. #ifdef USEDUMP
  16. # pragma load "Socket.dump"
  17. #else
  18. # include <Events.h>
  19. # include <Types.h>
  20. # include <Memory.h>
  21. # include <Stdio.h>
  22. # include <OSUtils.h>
  23.  
  24. # include <s_types.h>
  25. # include <neti_in.h>
  26. # include <neterrno.h>
  27. # include <s_file.h>
  28. # include <s_ioctl.h>
  29. # include <s_socket.h>
  30. # include <s_time.h>
  31. # include <s_uio.h>
  32. # include <unixlib.h>
  33.  
  34. # include "sock_str.h"
  35. # include "sock_int.h"
  36. #endif
  37.  
  38. #include <StdLib.h>
  39.  
  40. extern SocketPtr sockets;
  41. extern AllPb *pbList;
  42. extern short pbLast;
  43. extern StreamHashEntPtr streams;
  44. #ifndef COMP_CODEWAR
  45. extern SpinFn spinroutine;
  46. #endif
  47.  
  48. long errno_long; /* same as errno, but of known length */
  49.  
  50. /*
  51.  * sock_init() - initialize everything.
  52.  * BUG NOTE: returns error codes, but no one that calls it actually checks the return
  53.  * codes. probably bad.
  54.  */
  55. int sock_init()
  56. {
  57.     OSErr io;
  58.     int i;
  59.     
  60.     if (sockets != NULL)
  61.         return 0;
  62.  
  63.     sock_find_shep((StreamPtr) NULL);        /* load resident segment */
  64.             
  65.     /*
  66.      * call up driver
  67.      */
  68.     
  69.     xOpenDriver();
  70.     
  71. #if SOCK_UTIL_DEBUG >= 2
  72.     dprintf("sock_init: first time through\n");
  73.     dprintf("sock_init: allocating %d bytes for %d socket records\n",
  74.             NUM_SOCKETS * sizeof(SocketRecord),NUM_SOCKETS);
  75. #endif
  76.  
  77.     /* allocate storage for socket records */
  78.     sockets = (SocketPtr)NewPtrClear(NUM_SOCKETS * sizeof(SocketRecord));
  79.     if (sockets == NULL)
  80.         return(sock_err(ENOMEM));
  81.         
  82.     /* allocate storage for pbs */
  83.     pbList = (AllPb *)NewPtrClear(NUM_PBS * sizeof (AllPb));
  84.     if ( pbList == NULL )
  85.         return sock_err(ENOMEM);
  86.  
  87.     /* allocate storage for stream->socket hash table */
  88.     streams = (StreamHashEntPtr)NewPtrClear(NUM_SOCKETS * sizeof(StreamHashEnt));
  89.     if ( streams == NULL )
  90.         return(sock_err(ENOMEM));
  91.     
  92.     /* initialize them */
  93.     for (i=0; i<NUM_SOCKETS; i++)
  94.     {
  95.         sock_clear_fd(i);
  96.     }
  97.     
  98.     /* load the MacTCP name server resolver */
  99. #if SOCK_UTIL_DEBUG >= 2
  100.     dprintf("sock_init: loading name server resolver\n");
  101. #endif
  102.  
  103.     io = OpenResolver(NULL);
  104.     
  105. #if SOCK_UTIL_DEBUG >= 1
  106.     if (io != noErr)
  107.         dprintf("sock_init: failed to load name server resolver code %d\n",io);
  108.     else
  109.         dprintf("sock_init: loaded name server ok.\n");
  110. #endif
  111.  
  112.     /* establish our clean up man */
  113.     atexit(sock_close_all);
  114.     
  115. #if SOCK_UTIL_DEBUG >= 1
  116.     dprintf("sock_init: exiting.\n");
  117. #endif
  118.         return 0;
  119. }
  120.  
  121. /*
  122.  * sock_close_all() - Close all sockets (aborting their connections) and
  123.  *                    release dynamic storage.
  124.  */
  125. void sock_close_all()
  126. {
  127.     int s;
  128.     SocketPtr sp;
  129.     TCPiopb        *tpb;
  130.     UDPiopb        *upb;
  131.  
  132.     for (s = 0 ; s < NUM_SOCKETS ; ++s) 
  133.     {
  134.         sp = sockets+s;
  135.         if (sp->status == SOCK_STATUS_USED) 
  136.         {
  137.             switch(sp->protocol) 
  138.             {
  139.                 case IPPROTO_UDP:
  140.                     upb = (UDPiopb *)sock_fetch_pb(sp);        /* must succeed */
  141.                     (void) xUDPRelease(sp);
  142.                     break;
  143.                     
  144.                 case IPPROTO_TCP:
  145.                     tpb = (TCPiopb *)sock_fetch_pb(sp);
  146.                     (void) xTCPRelease(tpb);
  147.                     break;
  148.             }
  149.             sock_clear_fd(s);
  150.         }
  151.     }
  152.     DisposPtr((Ptr)sockets);
  153.     DisposPtr((Ptr)streams);
  154.     DisposPtr((Ptr)pbList);
  155.     
  156.     /* release name server resources */
  157.     (void) CloseResolver();
  158. }
  159.  
  160. /*
  161.  *    sock_free_fd()
  162.  *
  163.  *    Get the next free file descriptor >= f.  Return -1 if none available.
  164.  */
  165. int sock_free_fd(
  166.     int f)
  167. {
  168.     int s;
  169.  
  170.     for (s = f; s < NUM_SOCKETS; s++)
  171.           if (! is_used(sockets+s))
  172.             return(s);
  173.     return(-1);
  174. }
  175.  
  176. /*
  177.  *    sock_dup_fd() - duplicate a socket table entry. Very dangerous (ie. dumb) routine.
  178.  *  IMPORTANT: It is up to the caller to straighten out the StreamHash table
  179.  *  to reflect the new situation.  Nasty things may happen if s/he doesn't.
  180.  */
  181. void sock_dup_fd(
  182.     int    s,
  183.     int    s1)
  184. {
  185.     BlockMove((Ptr)(sockets+s), (Ptr)(sockets+s1), sizeof(SocketRecord));    
  186.     sock_init_fd(s1);
  187. }
  188.  
  189. /*
  190.  *    sock_clear_fd() - Clear out a socket table entry freeing any 
  191.  *                    storage attached to it.
  192.  *  
  193.  *                    Then re-initialize it for reuse.
  194.  */
  195. void sock_clear_fd(
  196.     int s)
  197. {
  198.     SocketPtr sp = sockets+s;
  199.     StreamHashEntPtr shep;
  200.     
  201.     if ((shep=sock_find_shep(sp->stream))!=NULL)    /* in hash table */
  202.         shep->stream = -1;                    /* mark as deleted */
  203.         
  204.     bzero(sp, sizeof(SocketRecord));
  205.     sp->sa.sin_family = AF_UNSPEC;
  206.     sp->status &= ~SOCK_STATUS_USED;
  207.  
  208.     sock_init_fd(s);
  209. }
  210.  
  211.     
  212. /*
  213.  * Close relative of sock_find_shep, sock_new_shep returns a StreamHashEntPtr
  214.  * that is unused and most appropriate for the passed stream.
  215.  */
  216. StreamHashEntPtr sock_new_shep(StreamPtr newStream)
  217.     {
  218.     StreamHashEntPtr    shep;
  219.     int        counter,start;
  220.     
  221.     /* start at hash point */
  222.     start = counter = (newStream & (SOCKETS_MASK << 3) ) >> 3;    /* extract some arbitrary bits */
  223.     shep = streams + counter;
  224.     do
  225.          {
  226.         /*
  227.          * scan till we find entry or unused or deleted slot.
  228.          */
  229.         if ( (shep->stream == newStream) || (shep->stream == (StreamPtr) NULL) || 
  230.             (shep->stream == -1) )
  231.             break;
  232.         else
  233.             {
  234.             counter = (counter+1) & SOCKETS_MASK;
  235.             if (counter)
  236.                 shep++;
  237.             else
  238.                 shep = streams;
  239.             }
  240.         }
  241.     while(counter != start);
  242.     
  243.     if ( (shep->stream == (StreamPtr) NULL ) || (shep->stream == -1 ) )
  244.         return shep;
  245.     else
  246.         return NULL;    /* error: already in table or table full. Should never happen. (right...) */
  247.     }
  248.     
  249. /*
  250.  * sock_fetch_pb grabs a pb from the global pool, making sure it isn't
  251.  * used. It may block for a long time if all pb are in progress. Declared
  252.  * void * because I'm getting sick of typecasting every goddamn little pointer
  253.  */ 
  254. void *sock_fetch_pb(SocketPtr sp)
  255.     {
  256.     AllPb    *pb;
  257.     do
  258.         {
  259.         pbLast ++;
  260.         if (pbLast == NUM_PBS)
  261.             pbLast = 0;
  262.         
  263.         pb = pbList + pbLast;
  264.         } 
  265.     while ( pb->tcp.ioResult == inProgress );
  266.     
  267.     pb->tcp.tcpStream = sp->stream;        /* all the calls have the stream at the same offset */
  268.                                         /* thank god. */
  269.     return ((void *)pb);
  270.     }
  271.  
  272.  
  273. void sock_init_fd(
  274.     int s)
  275. {
  276.     SocketPtr sp = sockets+s;
  277.  
  278.     sp->fd = s;
  279. }
  280.  
  281.  
  282. /*
  283.  * Convert a MacTCP err code into a unix error code, if needed. Otherwise it
  284.  * will pass thru unmolested.
  285.  */
  286. int sock_err( int MacTCPerr )
  287.     {
  288.     switch ( MacTCPerr )
  289.         {
  290.         case ipBadLapErr:
  291.         case ipBadCnfgErr:
  292.         case ipNoCnfgErr:
  293.         case ipLoadErr:
  294.         case ipBadAddr:
  295.             errno_long = ENXIO;            /* device not configured */    /* a cheap cop out */
  296.             break;
  297.             
  298.         case connectionClosing:
  299.             errno_long = ESHUTDOWN;        /* Can't send after socket shutdown */
  300.             break;
  301.  
  302.         case connectionExists:
  303.             errno_long = EISCONN;        /* Socket is already connected */
  304.             break;
  305.  
  306.         case connectionTerminated:
  307.             errno_long = ENOTCONN;        /* Connection reset by peer */  /* one of many possible */
  308.             break;
  309.  
  310.         case openFailed:
  311.             errno_long = ECONNREFUSED;    /* Connection refused */
  312.             break;
  313.  
  314.         case duplicateSocket:        /* technically, duplicate port */
  315.             errno_long = EADDRINUSE;        /* Address already in use */
  316.             break;
  317.             
  318.         case ipDestDeadErr:
  319.             errno_long = EHOSTDOWN;        /* Host is down */
  320.             break;
  321.             
  322.         case ipRouteErr:
  323.             errno_long = EHOSTUNREACH;    /* No route to host */
  324.             break;
  325.             
  326.         default:
  327.             errno_long = MacTCPerr;        /* cop out; an internal err, unix err, or no err */
  328.             break;
  329.         }
  330. #if    SOCK_UTIL_DEBUG >= 1
  331.     dprintf("SOCK  error %d\n", errno_long);
  332. #endif
  333.  
  334.     //errno = errno_long;
  335.     return (-1);
  336.     }
  337.  
  338. /*
  339.  *  sock_copy_addr
  340.  */
  341. void sock_copy_addr(
  342.     void *from,
  343.     void *to,
  344.     Int4 *tolen)
  345. {
  346.     *tolen = min(*tolen, sizeof(struct sockaddr_in));
  347.     BlockMove((Ptr)from, (Ptr)to, *tolen);
  348. }
  349.  
  350.  
  351. #if SOCK_UTIL_DEBUG > 1
  352. /*
  353.  * print the socket records.
  354.  */
  355. void sock_dump()
  356. {
  357.     int s;
  358.     char title[20];
  359.  
  360.     for (s=0; s<NUM_SOCKETS; s++) 
  361.     {
  362.         if (! is_used(sockets+s))
  363.             continue;
  364.         sprintf(title,"%2d",s);
  365.         sock_print(title,sockets+s);
  366.     }
  367. }
  368.  
  369. void sock_print(
  370.     char *title,
  371.     SocketPtr sp)
  372. {
  373.     dprintf("%s: %08x %s %08x addr %08x/%d %08x/%d state %d/%d err %d\n",
  374.             title, sp, 
  375.             (sp->protocol == IPPROTO_UDP ? "udp" : "tcp"),
  376.             (sp->protocol == IPPROTO_UDP ? sp->pb.udp.udpStream : sp->pb.tcp.tcpStream),
  377.             sp->sa.sin_addr.s_addr,sp->sa.sin_port,
  378.             sp->peer.sin_addr.s_addr,sp->peer.sin_port,
  379.             sp->sstate,xTCPState(&sp->pb),
  380.             sp->asyncerr);
  381. }
  382. #endif
  383.  
  384.  
  385.  
  386. #ifndef COMP_CODEWAR
  387. #pragma segment SOCK_RESIDENT
  388. #endif
  389. /*
  390.  * sock_find_shep returns a StreamHashEntPtr for the passed
  391.  * stream. Will return 0 if the stream doesn't exits.
  392.  */
  393. StreamHashEntPtr sock_find_shep(StreamPtr theStream)
  394.     {
  395.     StreamHashEntPtr    shep;
  396.     int     counter,start;
  397.     
  398.     if (!goodptr(theStream))                /* DO NOT CHANGE THESE TWO LINES! */
  399.         return NULL;                        /* used to load the resident segment */
  400.         
  401.     /* start at hash point */
  402.     start = counter = (theStream & (SOCKETS_MASK << 3) ) >> 3;    /* extract a bunch of arbitrary bits */
  403.     shep = streams + counter;
  404.     do
  405.          {
  406.         /*
  407.          * scan till we find entry or unused slot. Uses linear
  408.          * collision resolution because it's too complicated to
  409.          * do anything else for this small of a hash table.
  410.          */
  411.         if ( (shep->stream == theStream) || (shep->stream == (StreamPtr) NULL))
  412.             break;
  413.         else
  414.             {
  415.             counter = (counter+1) & SOCKETS_MASK;
  416.             if (counter)
  417.                 shep++;
  418.             else
  419.                 shep = streams;
  420.             }
  421.         }
  422.     while(counter != start);
  423.     
  424.     if ( shep->stream == theStream ) /* found it */
  425.         return shep;
  426.     else
  427.         return NULL;
  428.     }
  429.